package config

// TerraformExtraArguments sets a list of arguments to pass to Terraform if command fits any in the `Commands` list
type TerraformExtraArguments struct {
	Name             string             `hcl:"name,label" cty:"name"`
	Arguments        *[]string          `hcl:"arguments,attr" cty:"arguments"`
	RequiredVarFiles *[]string          `hcl:"required_var_files,attr" cty:"required_var_files"`
	OptionalVarFiles *[]string          `hcl:"optional_var_files,attr" cty:"optional_var_files"`
	Commands         []string           `hcl:"commands,attr" cty:"commands"`
	EnvVars          *map[string]string `hcl:"env_vars,attr" cty:"env_vars"`
}

// Hook specifies terraform commands (apply/plan) and array of os commands to execute
type Hook struct {
	Name       string   `hcl:"name,label" cty:"name"`
	Commands   []string `hcl:"commands,attr" cty:"commands"`
	Execute    []string `hcl:"execute,attr" cty:"execute"`
	RunOnError *bool    `hcl:"run_on_error,attr" cty:"run_on_error"`
	WorkingDir *string  `hcl:"working_dir,attr" cty:"working_dir"`
	Quiet      bool     `hcl:"quiet,optional" cty:"quiet"`
}

type ErrorHook struct {
	Name       string   `hcl:"name,label" cty:"name"`
	Commands   []string `hcl:"commands,attr" cty:"commands"`
	Execute    []string `hcl:"execute,attr" cty:"execute"`
	OnErrors   []string `hcl:"on_errors,attr" cty:"on_errors"`
	WorkingDir *string  `hcl:"working_dir,attr" cty:"working_dir"`
}

// TODO 改为运行时字段解析
type Terraform struct {
	ExtraArgs   []TerraformExtraArguments `hcl:"extra_arguments,block"`
	BeforeHooks []Hook                    `hcl:"before_hook,block"`
	AfterHooks  []Hook                    `hcl:"after_hook,block"`
	ErrorHooks  []ErrorHook               `hcl:"error_hook,block"`
}

func indexOf[T ErrorHook | Hook | TerraformExtraArguments | Function](fn func(obj T) string, name string, objs []T) int {
	for idx, obj := range objs {
		if fn(obj) == name {
			return idx
		}
	}
	return -1
}

func MergeTerraform(a, b *Terraform) *Terraform {
	c := new(Terraform)
	for _, t := range []*Terraform{a, b} {
		if t == nil {
			continue
		}
		for _, arg := range t.ExtraArgs {
			idx := indexOf[TerraformExtraArguments](func(obj TerraformExtraArguments) string { return obj.Name }, arg.Name, c.ExtraArgs)
			if idx == -1 {
				c.ExtraArgs = append(c.ExtraArgs, arg)
			} else {
				c.ExtraArgs[idx] = arg
			}
		}
		for _, hook := range t.BeforeHooks {
			idx := indexOf[Hook](func(obj Hook) string { return obj.Name }, hook.Name, c.BeforeHooks)
			if idx == -1 {
				c.BeforeHooks = append(c.BeforeHooks, hook)
			} else {
				c.BeforeHooks[idx] = hook
			}
		}
		for _, hook := range t.AfterHooks {
			idx := indexOf[Hook](func(obj Hook) string { return obj.Name }, hook.Name, c.AfterHooks)
			if idx == -1 {
				c.AfterHooks = append(c.AfterHooks, hook)
			} else {
				c.AfterHooks[idx] = hook
			}
		}
		for _, hook := range t.ErrorHooks {
			idx := indexOf[ErrorHook](func(obj ErrorHook) string { return obj.Name }, hook.Name, c.ErrorHooks)
			if idx == -1 {
				c.ErrorHooks = append(c.ErrorHooks, hook)
			} else {
				c.ErrorHooks[idx] = hook
			}
		}
	}
	return c
}
